package testgrp;

import java.util.concurrent.ExecutionException;

import co.paralleluniverse.strands.SuspendableCallable;
import co.paralleluniverse.strands.SuspendableRunnable;
import co.paralleluniverse.strands.channels.Channels;
import co.paralleluniverse.strands.channels.IntChannel;

import co.paralleluniverse.fibers.Fiber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Increasing-Echo Quasar Example
 *
 * @author circlespainter
 */
public class QuasarIncreasingEchoApp {

  private static final Logger log = LoggerFactory.getLogger(QuasarIncreasingEchoApp.class);

  static public Integer doAll() throws ExecutionException, InterruptedException {
    final IntChannel increasingToEcho = Channels
        .newIntChannel(0); // Synchronizing channel (buffer = 0)
    final IntChannel echoToIncreasing = Channels
        .newIntChannel(0); // Synchronizing channel (buffer = 0)

    Fiber<Integer> increasing = new Fiber<>("INCREASER", (SuspendableCallable<Integer>) () -> {
      ////// The following is enough to test instrumentation of synchronizing methods
      // synchronized(new Object()) {}

      int curr = 0;
      for (int i = 0; i < 10; i++) {
        Fiber.sleep(10);
        log.info("INCREASER sending: " + curr);
        increasingToEcho.send(curr);
        curr = echoToIncreasing.receive();
        log.info("INCREASER received: " + curr);
        curr++;
        log.info("INCREASER now: " + curr);
      }
      log.info("INCREASER closing channel and exiting");
      increasingToEcho.close();
      return curr;
    }).start();

    Fiber<Void> echo = new Fiber<Void>("ECHO", (SuspendableRunnable) () -> {
      Integer curr;
      while (true) {
        Fiber.sleep(1000);
        curr = increasingToEcho.receive();
        log.info("ECHO received: " + curr);

        if (curr != null) {
          log.info("ECHO sending: " + curr);
          echoToIncreasing.send(curr);
        } else {
          log.info("ECHO detected closed channel, closing and exiting");
          echoToIncreasing.close();
          return;
        }
      }
    }).start();

    try {
      increasing.join();
      echo.join();
    } catch (ExecutionException | InterruptedException e) {
      e.printStackTrace();
    }

    return increasing.get();
  }

  static public void main(String[] args) throws ExecutionException, InterruptedException {
    doAll();
  }
}